package example;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.core.FileItem;
import org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletDiskFileUpload;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.IO;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FileServlet extends HttpServlet {
    DiskFileItemFactory factory = new DiskFileItemFactory.Builder().get();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String requestURI = req.getRequestURI();

        File file = new File("." + requestURI);
        if (!file.exists()) {
            // 返回个错误页面 todo，路径不存在
        }
        if (file.isDirectory()) {  // 如果是文件夹，列出文件夹的文件
            File[] files = file.listFiles();

            List<String> fileNames = Arrays.stream(files).map(File::getName).sorted().collect(Collectors.toList());
            if (!"/".equals(requestURI)) { // 根目录不显示上级目录
                fileNames.add(0, "../");
            }
            StringBuilder respBody = getBody(requestURI, fileNames);
            resp.getWriter().println(respBody);
        } else { // 如果是文件，直接下载文件
            resp.setContentType("application/octet-stream");
            resp.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(file.getName(), "UTF-8") + "\"");

            IO.copy(Files.newInputStream(file.toPath()), resp.getOutputStream());
        }
    }

    private static StringBuilder getBody(String requestURI, List<String> fileNames) {
        StringBuilder respBody = new StringBuilder();
        respBody.append("<html>");
        respBody.append("<head>");
        respBody.append("<base href='" + requestURI + (requestURI.endsWith("/") ? "" : "/") + "'>");
        respBody.append("</head>");
        respBody.append("<body>");
        respBody.append("<h1>How are you,I am a javaer,And you?</h1>");
        respBody.append("<ol>");
        fileNames.forEach(fileName -> respBody.append("<li><a href='").append(fileName).append("'>").append(fileName).append("</a></li>"));
        respBody.append("</ol>");
        respBody.append("<form enctype='multipart/form-data' method='POST'>");
        respBody.append("<input type='file' name='file' multiple onchange='this.form.submit()' > ");
        respBody.append("</form>");
        respBody.append("</body>");
        respBody.append("</html>");
        return respBody;
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
        try {
            String requestURI = req.getRequestURI();

            JakartaServletDiskFileUpload upload = new JakartaServletDiskFileUpload(factory);
            List<DiskFileItem> items = upload.parseRequest(req);
            // 保存文件的 目标文件夹
            File targetDir = new File("." + requestURI);
            // 处理文件项
            for (DiskFileItem item : items) {
                if (item.isFormField()) {
                    continue;
                }
                File toFile = getFile(item, targetDir);
                item.write(toFile.toPath());
            }
            resp.sendRedirect(requestURI);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 计算出文件名。文件名重复时,需要计算新文件名
     */
    private static File getFile(FileItem item, File targetDir) {
        String name = item.getName();
        File file = new File(targetDir, name);
        if (!file.exists()) {
            return file;
        }
        // 如果存在，则重命名为
        // xxx(2).yyy
        // 或者xxx(3).yyy  等等
        file = null;
        int pos = name.lastIndexOf('.');// 找到最后一个.的位置，前面字符是文件名，后面字符是文件类型 xxx.yyy
        if (pos == -1) {
            pos = name.length();
        }
        for (int i = 2; i <= 10/*最多10次*/; i++) {
            File tempFile = new File(targetDir, name.substring(0, pos) + "(" + i + ")" + name.substring(pos));
            if (tempFile.exists()) {// 文件名重复，继续+1
                continue;
            }
            file = tempFile;
            break;
        }
        if (file == null) {
            // todo 错误页面 文件重名。10次都不够
        }
        return file;
    }

    public static void main(String[] args) throws Exception {
        Server server = new Server(80);

        ServletContextHandler context = new ServletContextHandler();
        context.addServlet(FileServlet.class, "/");

        server.setHandler(context);
        server.start();
        server.join();
    }
}